#include "dynamicqobject.h"
#include "QDebug"
#include <QMetaMethod>
#include <QVariant>

DynamicQObject::DynamicQObject(QObject *mapToObject, const char *signalCatchMethod, QObject *parent) :
    QObject(parent), m_mapTo(mapToObject), m_catchMethod(signalCatchMethod)
{}


bool DynamicQObject::connectDynamicSlot(QObject *object,
                                        const char *signal,
                                        const QString &slot)
{
    if (containsSlot(slot))
        return false;
    if (signal[0] != '2')
        return false;

    QByteArray theSignal = QMetaObject::normalizedSignature(&signal[1]);
    int signalId = object->metaObject()->indexOfSignal(theSignal);
    if (signalId < 0)
        return false;

    QVector<int> parameterTypes;
    QMetaMethod signalMethod = object->metaObject()->method(signalId);
    for (int i = 0; i < signalMethod.parameterCount(); ++i)
        parameterTypes.push_back(signalMethod.parameterType(i));

    int slotId = m_slotList.size();
    m_slotList.push_back({slot, parameterTypes});

    return QMetaObject::connect(object, signalId,
                                this, slotId + metaObject()->methodCount());
}

bool DynamicQObject::containsSlot(const QString &name)
{
    for (int i = 0; i < m_slotList.count(); ++i)
        if (m_slotList[i].name == name)
            return true;
    return false;
}

//bool DynamicQObject::connectDynamicSignal(int signalId, QObject *obj, const char *slot)
//{
//    int slotId = obj->metaObject()->indexOfSlot(&slot[1]); // without 1 added by SLOT() macro
//    if (slotId < 0)
//        return false;

//    return QMetaObject::connect(this, signalId + metaObject()->methodCount(), obj, slotId);
//}

int DynamicQObject::qt_metacall(QMetaObject::Call call, int id, void **arguments)
{
    id = QObject::qt_metacall(call, id, arguments);
    if (id < 0 || call != QMetaObject::InvokeMetaMethod)
        return id;
    Q_ASSERT(id < m_slotList.size());

    const slot_t &slotInfo = m_slotList[id];
    QVariantList parameters;
    for (int i = 0; i < slotInfo.parameterTypes.count(); ++i) {
        void *parameter = arguments[i + 1];
        parameters.append(QVariant(slotInfo.parameterTypes[i], parameter));
    }

    QMetaObject::invokeMethod(m_mapTo, m_catchMethod,
                              Q_ARG(QString, slotInfo.name),
                              Q_ARG(QVariantList, parameters));
    return -1;
}

//void DynamicQObject::emitSignal(int signalId, void **arguments)
//{
//    if (signalId >= 0) {
//        QMetaObject::activate(this, metaObject(), signalId + metaObject()->methodCount(),
//            arguments);
//    }
//}
